package com.kzj.domain.bp;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.kzj.common.constant.GlobalConstant;
import com.kzj.common.exception.MyException;
import com.kzj.domain.Equation;
import com.kzj.domain.Exercises;
import io.swagger.models.auth.In;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

public class ExercisesBP extends Exercises {
    /**
     * 算式存储数组
     */
    private List<EquationBP> equationBPList =new ArrayList<>();
    public ExercisesBP(){};
    public ExercisesBP(Integer number, Integer type, Integer grade){
        if(grade>6||grade<1)
            throw new MyException(GlobalConstant.GRADE_ERROR);
        if(number>100||number<1)
            throw new MyException(GlobalConstant.NUMBER_ERROR);
        if(grade==1&&(type==Exercises.MUL||type==Exercises.DIV))
            throw new MyException(GlobalConstant.GRADE_FAULTY);
        int[] addUpperLimit={30,50,100,200,500,1000};
        int[] addDownLimit={0,0,0,-50,-100,-300};
        int[] subUpperLimit={30,50,100,200,500,1000};
        int[] subDownLimit={0,0,0,-50,-100,-300};
        int[] mulUpperLimit={0,30,40,60,100,150};
        int[] mulDownLimit={0,0,0,-10,-30,-50};
        int[] divUpperLimit={0,30,40,60,100,150};
        int[] divDownLimit={0,0,0,-10,-30,-50};
        int[] mixUpperLimit={30,30,40,60,100,150};
        int[] mixDownLimit={0,0,0,-10,-30,-50};
        int[] numberArr={2,2,3,3,4,5};
        int[] decimalPlaceArr={0,0,1,2,2,2};
        int[] addUpperLimitResult={60,100,300,600,1200,3000};
        int[] addDownLimitResult={0,0,0,-150,-200,-500};
        int[] subUpperLimitResult={60,100,300,600,1200,3000};
        int[] subDownLimitResult={0,0,0,-150,-200,-500};
        int[] mulUpperLimitResult={0,500,1000,2000,2500,3000};
        int[] mulDownLimitResult={0,-500,-1000,-2000,-2500,-3000};
        int[] divUpperLimitResult={0,500,1000,2000,2500,3000};
        int[] divDownLimitResult={0,-500,-1000,-2000,-2500,-3000};
        int[] mixUpperLimitResult={60,500,1000,2000,2500,3000};
        int[] mixDownLimitResult={0,-500,-1000,-2000,-2500,-3000};
        Random random = new Random();
        if(type.equals(Exercises.ADDITION))
        {
            while(equationBPList.size()<number)
            {
                Integer num=random.nextInt(numberArr[grade-1]-2+1)+2;
                EquationBP equationBP = EquationBP.generateAdditionEquation(addUpperLimit[grade - 1], addDownLimit[grade - 1], num, decimalPlaceArr[grade - 1]);
                if(judgeResultRange(equationBP,addUpperLimitResult[grade-1],addDownLimitResult[grade-1]));
                    this.add(equationBP);
            }
        }
        else if(type.equals(Exercises.SUBDUCTION))
        {
            while(equationBPList.size()<number)
            {
                Integer num=random.nextInt(numberArr[grade-1]-2+1)+2;
                EquationBP equationBP = EquationBP.generateSubstractEquation(subUpperLimit[grade - 1], subDownLimit[grade - 1], num, decimalPlaceArr[grade - 1]);
                if(judgeResultRange(equationBP,subUpperLimitResult[grade-1],subDownLimitResult[grade-1]))
                    this.add(equationBP);
            }
        }
        else if(type.equals(Exercises.MUL))
        {
            while(equationBPList.size()<number)
            {
                Integer num=random.nextInt(numberArr[grade-1]-2+1)+2;
                EquationBP equationBP = EquationBP.generateMulEquation(mulUpperLimit[grade - 1], mulDownLimit[grade - 1], num, decimalPlaceArr[grade - 1]);
                if(judgeResultRange(equationBP,mulUpperLimitResult[grade-1],mulDownLimitResult[grade-1]))
                    this.add(equationBP);
            }
        }
        else if(type.equals(Exercises.DIV))
        {
            while(equationBPList.size()<number)
            {
                Integer num=random.nextInt(numberArr[grade-1]-2+1)+2;
                EquationBP equationBP = EquationBP.generateDivEquation(divUpperLimit[grade - 1], divDownLimit[grade - 1], num, decimalPlaceArr[grade - 1]);
                if(judgeResultRange(equationBP,divUpperLimitResult[grade-1],divDownLimitResult[grade-1]))
                    this.add(equationBP);
            }
        }
        else if(type.equals(Exercises.MIX))
        {
            while(equationBPList.size()<number)
            {
                Integer num=random.nextInt(numberArr[grade-1]-2+1)+2;
                EquationBP equationBP;
                if(grade==1)
                {
                     equationBP = EquationBP.generateEquationByGrandeOne(mixUpperLimit[grade - 1], mixDownLimit[grade - 1], num, decimalPlaceArr[grade - 1]);
                    System.out.println(equationBP.toString());
                }
                else {
                     equationBP = EquationBP.generateEquation(mixUpperLimit[grade - 1], mixDownLimit[grade - 1], num, decimalPlaceArr[grade - 1]);
                }
                if(judgeResultRange(equationBP,mixUpperLimitResult[grade-1],mixDownLimitResult[grade-1]))
                 this.add(equationBP);
            }
        }
        else throw new MyException(GlobalConstant.EXERCISES_TYPE_ERROR);
    }
    public boolean judgeResultRange(EquationBP equationBP,double upperLimit,double downLimit)
    {
        double result=Double.valueOf(EquationBP.calculateResult(equationBP)).doubleValue();
        return (result>=downLimit&&result<=upperLimit);
    }
    public static String getTypeToString(Integer type)
    {
        if(type.equals(Exercises.ADDITION))
        {
            return GlobalConstant.EXERCISES_TYPE_ADD;
        }
        else if(type.equals(Exercises.SUBDUCTION))
        {
            return GlobalConstant.EXERCISES_TYPE_SUB;
        }
        else if(type.equals(Exercises.MUL))
        {
            return GlobalConstant.EXERCISES_TYPE_MUL;
        }
        else if(type.equals(Exercises.DIV))
        {
            return GlobalConstant.EXERCISES_TYPE_DIV;
        }
        else if(type.equals(Exercises.MIX))
        {
            return GlobalConstant.EXERCISES_TYPE_MIX;
        }
        else if(type.equals(Exercises.ERROR_SET))
        {
            return GlobalConstant.EXERCISES_TYPE_ERROR_SET;
        }
        else return GlobalConstant.EXERCISES_TYPE_UNKNOWN;
    }
    public static String getTypeAndTimingToString(Exercises exercises)
    {
        Integer type=exercises.getType();
        if(type.equals(Exercises.ADDITION))
        {
            if(exercises.getTimingTime()!=null)
                return GlobalConstant.EXERCISES_TYPE_LIMIT_ADD;
            return GlobalConstant.EXERCISES_TYPE_ADD;
        }
        else if(type.equals(Exercises.SUBDUCTION))
        {
            if(exercises.getTimingTime()!=null)
                return GlobalConstant.EXERCISES_TYPE_LIMIT_SUB;
            return GlobalConstant.EXERCISES_TYPE_SUB;
        }
        else if(type.equals(Exercises.MUL))
        {
            if(exercises.getTimingTime()!=null)
                return GlobalConstant.EXERCISES_TYPE_LIMIT_MUL;
            return GlobalConstant.EXERCISES_TYPE_MUL;
        }
        else if(type.equals(Exercises.DIV))
        {
            if(exercises.getTimingTime()!=null)
                return GlobalConstant.EXERCISES_TYPE_LIMIT_DIV;
            return GlobalConstant.EXERCISES_TYPE_DIV;
        }
        else if(type.equals(Exercises.MIX))
        {
            if(exercises.getTimingTime()!=null)
                return GlobalConstant.EXERCISES_TYPE_LIMIT_MIX;
            return GlobalConstant.EXERCISES_TYPE_MIX;
        }
        else return GlobalConstant.EXERCISES_TYPE_UNKNOWN;
    }
    public List<Equation> getEquationList(Long exercisesId)
    {
        List<Equation> collect = this.equationBPList.stream().map(item -> {
            Equation equation = new Equation();
            long id = IdWorker.getId();
            equation.setId(id);
            equation.setExercisesId(exercisesId);
            equation.setContent(item.toString());
            equation.setAnswer(EquationBP.calculateResult(item));
            return equation;
        }).collect(Collectors.toList());
        return collect;
    }


    /**
     * 习题是否包含某个算式
     * @param obj 算式
     * @return ture: 习题已经包含该算式 false:习题不包含该算式
     */
    public boolean include(EquationBP obj)
    {
        boolean flag=false;
        for (EquationBP equationBP : equationBPList) {
            if(equationBP.equals(obj))
            {
                flag=true;
                break;
            }
        }
        return flag;
    }

    /**
     * 习题增加算式
     * @param obj 算式
     * @return ture:添加成功 false:添加失败(算式已包含或为空)
     */
    public boolean add(EquationBP obj)
    {
        if(obj==null||this.include(obj))
            return false;
        else{
            this.equationBPList.add(obj);
            return true;
        }
    }


    /**
     * 得到习题的算式数量
     * @return
     */
    public Integer size()
    {
        return this.equationBPList.size();
    }

    /**
     * 得到指定序号的算式(若序号不合理则返回null)
     * @param index 序号
     * @return 指定序号的算式
     */
    public EquationBP get(Integer index)
    {
        if(index>=this.equationBPList.size()||index<0)
            return null;
        return this.equationBPList.get(index);
    }

    /**
     * 得到指定序号的元素,并将其从算式存储数值中移出(若序号不合理则返回null)
     * @param index 序号
     * @return 指定序号的算式
     */
    public EquationBP pop(Integer index)
    {
        EquationBP equationBP = this.get(index);
        if(equationBP ==null)
            return null;
        this.equationBPList.remove((int)index);
        return equationBP;
    }
}
